package com.dynamic.mybatis.web.security;


import com.alibaba.fastjson2.JSON;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.Verification;
import com.dynamic.mybatis.core.metadata.DynamicConfiguration;
import com.dynamic.mybatis.core.session.DynamicSqlSessionTemplate;
import com.dynamic.mybatis.core.utils.StringUtils;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.util.DigestUtils;

import java.security.MessageDigest;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

public class SecurityParameterInterceptHandler {

    public static final String secret = "!FAFSDFD";
    public static final String session_context = "_session_context_";
    public static final String ts = "_ts_";
    public DynamicConfiguration configuration;
    MessageDigest md5;
    DynamicSqlSessionTemplate dynamicSqlSessionTemplate;
    //用户私有变量 key md5(jwt token)  value 回话参数
    Cache<String, SecurityParameter> securityParameter = Caffeine.newBuilder()
            .expireAfterAccess(30, TimeUnit.MINUTES)
            .removalListener((k, v, removalCause) -> {
                System.out.println("caffeine expired. " + k + "   " + v + "  " + removalCause);
            })
            .build();

    public SecurityParameterInterceptHandler(DynamicSqlSessionTemplate dynamicSqlSessionTemplate) {
        this.dynamicSqlSessionTemplate = dynamicSqlSessionTemplate;
        this.configuration = (DynamicConfiguration) dynamicSqlSessionTemplate.getSqlSession().getConfiguration();
/*        try {
            md5 = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }*/
    }

    public void setSecurityParameter(String namespace, String token, Object parameter) {
        securityParameter.put(getSecurityParameterKey(namespace, token), new SecurityParameter(parameter));
    }

    public String getSecurityParameterKey(String namespace, String token) {
        return DigestUtils.md5DigestAsHex((Objects.toString(namespace, "") + token).getBytes());
        // return new String(md5.digest((Objects.toString(namespace,"")+token).getBytes()));
    }


    public Object getSecurityParameter(String namespace, String token) {
        if (StringUtils.isEmpty(token)) {
            return null;
        }
        //获取token对应的本地缓存
        String key = getSecurityParameterKey(namespace, token);
        SecurityParameter parameter = securityParameter.getIfPresent(key);
        Object param = null;
        if (parameter != null) {
            parameter.setDateTime(System.currentTimeMillis());
            securityParameter.put(key, parameter);
            param = parameter.getParameter();
        } else {
            //验证token
            verifyToken(token);
        }
        return param;
    }

    public static String generateToken(Map<String, Object> payload) {
        payload.put(ts, System.currentTimeMillis());
        return JWT.create()
                .withClaim(session_context, JSON.toJSONString(payload))
                .sign(Algorithm.HMAC256(secret)); //签名 相当于秘钥
    }

    public Object getTokenParameter(String token) {
        DecodedJWT decodedJWT = verifyToken(token);
        String payload = decodedJWT.getClaim(session_context).asString();
        return JSON.parseObject(payload);
    }

    public DecodedJWT verifyToken(String token) {
        Verification verification = JWT.require(Algorithm.HMAC256(secret));
        return verification.build().verify(token);
    }


    class SecurityParameter {
        public SecurityParameter(Object parameter) {
            this.parameter = parameter;
            this.dateTime = System.currentTimeMillis();
        }

        private Object parameter;
        private long dateTime;//最后一次访问时间

        public Object getParameter() {
            return parameter;
        }

        public void setParameter(Object parameter) {
            this.parameter = parameter;
        }

        public long getDateTime() {
            return dateTime;
        }

        public void setDateTime(long dateTime) {
            this.dateTime = dateTime;
        }
    }


    public static void main(String[] args) {
        String secret = "!FAFSDFD";
        String secret1 = "!FAFSDFD";
        Map<String, Object> payload = new HashMap<>();
        payload.put("userId", 123456); //payload
        payload.put("username", "zhangSan");
        String sign = JWT.create()
                .withPayload(payload)
                .sign(Algorithm.HMAC256(secret)); //签名 相当于秘钥
        System.out.println(sign);

        Verification verification = JWT.require(Algorithm.HMAC256(secret1));
        DecodedJWT decodedJWT = verification.build().verify(sign);
        Map<String, Object> param = new HashMap<>();
        decodedJWT.getClaims().forEach((k, v) -> {
            param.put(k, decodedJWT.getClaim(k));
        });
    }
}
